/*
 * @Author: Robin
 * @Date: 2020-02-20 17:38:31
 * @LastEditors: Robin
 * @LastEditTime: 2020-02-21 12:55:25
 * @Description: 虚拟串口,仅适用与Linux/Mac
 */
package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"sync"

	"github.com/creack/pty"
	"golang.org/x/crypto/ssh/terminal"
)

var wg sync.WaitGroup

func main() {
	// 处理启动参数
	num := flag.Int("num", 1, "serial number")
	flag.Parse()
	for i := 0; i < *num; i++ {
		pty1, t1, err := pty.Open()
		if err != nil {
			log.Fatalln(err)
		}
		terminal.MakeRaw(int(t1.Fd())) // 设置为Raw模式,防止控制字符丢失
		pty2, t2, err := pty.Open()
		if err != nil {
			log.Fatalln(err)
		}
		terminal.MakeRaw(int(t2.Fd())) // 设置为Raw模式,防止控制字符丢失
		go tty1(t1, t2, pty1, pty2)
		go tty2(t1, t2, pty1, pty2)
		fmt.Println("Virtual Serial Port:", t1.Name(), "<===>", t2.Name())
	}
	wg = sync.WaitGroup{}
	wg.Add(1)
	wg.Wait()
}

// 串口1
func tty1(tty1, tty2, pty1, pty2 *os.File) {
	var n int
	var err error
	buf := make([]byte, 1024)
	for {
		n, err = pty1.Read(buf)
		if err != nil {
			log.Fatalln(tty1.Name(), "Read Error", err.Error())
		}
		_, err = pty2.Write(buf[:n])
		if err != nil {
			log.Fatalln(tty2.Name(), "Write Error", err.Error())
		}
	}
}

// 串口2
func tty2(tty1, tty2, pty1, pty2 *os.File) {
	var n int
	var err error
	buf := make([]byte, 1024)
	for {
		n, err = pty2.Read(buf)
		if err != nil {
			log.Fatalln(tty2.Name(), "Read Error", err.Error())
		}
		_, err = pty1.Write(buf[:n])
		if err != nil {
			log.Fatalln(tty1.Name(), "Write Error", err.Error())
		}
	}
}
